/*
 * $Id: MagnetMonitorProcessor.java,v 1.5 2009/10/27 22:58:03 afaichun Exp $
 * 
 * Copyright (C) 2008 General Electric Company. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of the General
 * Electric Company (GE). You shall not disclose this software and shall use it
 * only in accordance with the terms of the license agreement you entered into
 * with GE.
 * 
 * GE MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT. GE SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING, OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES.
 */
package com.ge.healthcare.autosc.processor.magmon;

import java.io.File;
import java.io.InputStream;

import com.ge.healthcare.autosc.common.ASCLogger;
import com.ge.healthcare.autosc.common.database.pojo.ActTask;
import com.ge.healthcare.autosc.common.dbLogger.StepLogger;
import com.ge.healthcare.autosc.common.exceptions.BasicException;
import com.ge.healthcare.autosc.common.exceptions.PpadsCommandUtilException;
import com.ge.healthcare.autosc.common.requestData.RequestDataSet;
import com.ge.healthcare.autosc.common.util.ASCFileHandler;
import com.ge.healthcare.autosc.common.util.PpadsCommandUtil;
import com.ge.healthcare.autosc.common.util.dataItem.IASCTextDataItem;
import com.ge.healthcare.autosc.processor.PrcCodeConstants;
import com.ge.healthcare.autosc.processor.exception.GuidanceLoaderException;
import com.ge.healthcare.autosc.processor.exception.MagnetMonitorProcessorException;
import com.ge.healthcare.autosc.processor.exception.MagnetMonitorSiteException;
import com.ge.healthcare.autosc.processor.shemjob.JobDirRequestData;
import com.ge.healthcare.autosc.processor.shemjob.guidance.dataset.MagmonDataSet;
import com.ge.healthcare.autosc.processor.shemjob.guidance.dataset.MinorEvent;
import com.ge.healthcare.autosc.processor.shemjob.guidance.loader.MagmonGuidanceLoader;
import com.ge.healthcare.autosc.processor.shemjob.reader.ShemTextReader;

public class MagnetMonitorProcessor implements IMagnetMonitorProcessor {

	private MagmonGuidanceLoader loader = null;
	
	private MagnetMonitorUtility utility = new MagnetMonitorUtility();
	
    /**
     * Object used for accessing and updating magnet monitor sites.
     */
    private IMagnetMonitorSite magMonSite = null;
    /**
     * The system identifier of the current site.  Null if there is no
     *  current site.
     */
    private String theSystemId = null;

    /**
     * The major function designator for the current event.  Null if there
     *  is no current event.
     */
    private String theMajorFunction = null;

    /**
     * The minor function designator for the current event.  Null if there
     *  is no current event.
     */
    private String theMinorFunction = null; 
	
    private boolean isJunit = false;

	public MagnetMonitorProcessor() throws GuidanceLoaderException {
		loader = new MagmonGuidanceLoader();
		loader.load();
	}

	public MagnetMonitorProcessor(boolean testFlag) throws GuidanceLoaderException {
		isJunit = testFlag;
		loader = new MagmonGuidanceLoader();
		if(testFlag) {
			loader.loadForTest();
		} else {
			loader.load();
		}
	}
	
	public void cleanUp() {
        if ( magMonSite != null )
        {
            magMonSite.cleanUp();
            magMonSite = null;
        }
	}

	public void selectEvent(String majorFunction, String minorFunction) {
		theMajorFunction = majorFunction;
        theMinorFunction = verifyValidName( minorFunction, "Task identifier" );
        StepLogger.addStepLog("Service: " + majorFunction + ", task: " + minorFunction);

	}
	
	public String getEventMajorFunction() {
		return theMajorFunction;
	}

	public String getEventMinorFunction() {
		return theMinorFunction;
	}
	
	public void selectSite(String systemId) {
		theSystemId = systemId;
		theSystemId = verifyValidName( systemId, "System identifier" );
		StepLogger.addStepLog("Process ShemJob for systemId: " + systemId);
	}

	public String getSite() {
		return theSystemId;
	}
	
    /**
     * Get the specified data item from the site.  This is a convenience
     *  method so only the magnet monitor object directly accesses the site.
     *
     * @param key The key used to identified the data item.
     *
     * @return The specified data item.
     *
     * @exception AscServiceAbortException If no site is currently selected.
     */
    public IASCTextDataItem getSiteDataItem( String key )
        throws MagnetMonitorProcessorException
    {
    	try {
    		return magMonSite.get( key );
    	} catch (MagnetMonitorSiteException mmse) {
    		throw new MagnetMonitorProcessorException(mmse);
    	}
    }
	
	public void shutDownInstance() {
		return;
	}

    /**
     * Process the currently selected event for the currently
     *  selected site.
     *
     * @exception AscServiceAbortException If an error is detected
     *  processing the event.
     */
	public void processCurrentEvent() 
		throws MagnetMonitorProcessorException{
		verifyRegistered();
		MinorEvent event = loader.getMinorEvent(this.theMajorFunction, this.theMinorFunction);
		if(event != null) {
			StepLogger.addStepLog("Process event: " + event.toString());
			try {
				MagnetMonitorEventProcessor processor =
					new MagnetMonitorEventProcessor(this.theSystemId,
													this.theMajorFunction,
													this.theMinorFunction,
													loader,
													magMonSite);
				processor.process(event);
				StepLogger.addStepLog("Process event successfully: " + event.toString());
			} catch (MagnetMonitorProcessorException mmpe) {
				throw new MagnetMonitorProcessorException("Failed processing minor event. MinorEvent: " + 
	        			event.toString(), mmpe,
	        			PrcCodeConstants.getCode(mmpe, PrcCodeConstants.PRC_F_SHM_006));
			}
		} else {
			throw new MagnetMonitorProcessorException("Cannot find minor event. Major function: " + 
					theMajorFunction + ", minor function: " + theMinorFunction);
		}
	}


    /**
     * Process a single data set.  This provides a single set of
     *  textual data to the magnet monitor.  This method will close
     *  the input reader before returning.
     *
     * @param key The key used to identify the data set being processed.
     *
     * @param inputReader The reader used to read the data set.
     *
     * @exception AscServiceAbortException If an error is detected
     *  processing the data set.
     */
    public void processDataSet( ActTask task, String key, ShemTextReader inputReader, RequestDataSet requestDataSet )
        throws BasicException
    {
    	String methodName = "processDataSet";
    	InputStream rawSource = requestDataSet.openDataSet();
    	try{
			inputReader.open(requestDataSet.getName(), rawSource, utility, this);
			
	    	verifyRegistered();
	        MagmonDataSet magMonDataSet = loader.getMagmonDataSet(key);
	        StepLogger.addStepLog("Process data set for datasource " + key);
	        
	        if(magMonDataSet != null) {
	        	ASCLogger.info(this.getClass(), methodName, "Process data set: " + magMonDataSet.toString());
	        	try {
	        		File sourceDir = requestDataSet.getSourceFile().getParentFile();
	        		JobDirRequestData jobDirData = new JobDirRequestData(task, sourceDir);
	        		MagnetMonitorDataProcessor processor = 
		            				new MagnetMonitorDataProcessor(jobDirData, magMonSite, magMonDataSet);
		            processor.process(key, inputReader, task);
		            ASCLogger.info(this.getClass(), methodName, "Process data set successfully: " + magMonDataSet.toString());
		        } catch (MagnetMonitorProcessorException mmpe) {
		        	throw new MagnetMonitorProcessorException("Failed processing data set. DataSet: " + 
		        			magMonDataSet.toString(), mmpe, 
		        			PrcCodeConstants.getCode(mmpe, PrcCodeConstants.PRC_F_SHM_005));
		        }
	        } else {
	        	throw new MagnetMonitorProcessorException("Cannot find data set with key " + key, PrcCodeConstants.PRC_F_SHM_012);
	        }
    	}finally{
    		ASCFileHandler.closeInputStream(rawSource);
    	}
    }
    
	public void verifyRegistered() throws MagnetMonitorProcessorException {
		
        verifyMagnetMonitorSiteObject();
        if ( !magMonSite.exists() )
        {
            String message = theSystemId + " not found on PPADS!";
            try {
            	PpadsCommandUtil.postPpadsEvent(theSystemId, PpadsCommandUtil.UNREGISTERED_SITE, this.theMinorFunction);
            } catch(PpadsCommandUtilException pcue) {
            	throw new MagnetMonitorProcessorException(pcue);
            }
            throw new MagnetMonitorProcessorException(message, PrcCodeConstants.PRC_F_SHM_011);
        }
	}

    /**
     * Make sure that a string is a valid name.  This means that the
     *  string is non-null, non-empty, and does not contain any illegal
     *  characters for a command-line argument or a file name.
     * Report an error only if there are any illegal characters for
     *  a command-line argument or a file name.
     *
     * @param source Source string to test.
     *
     * @param errorLabel Text used to describe the string in the error message.
     *
     * @return The source string if okay, null if the source string is null,
     *   empty, or contains any illegal characters for a command-line
     *   argument or a file name.
     */
    private String verifyValidName( String source, String errorLabel )
    {
    	String methodName = "verifyValidName";
        if ( source == null )
        {
            return null;
        }
        if ( source.equals("") )
        {
            return null;
        }
        char[] checkList = new char[] { ' ', '/', '\\', '\"', '\'' };
        for ( int idx = 0; idx < checkList.length; idx += 1 )
        {
            if ( source.indexOf( checkList[idx] ) != -1 )
            {
                String message = new StringBuffer().append(errorLabel)
                				.append(" \"")
                				.append(source)
                				.append("\" contains invalid character \"")
                				.append(checkList[idx])
                				.append("\"").toString();
                ASCLogger.error(this.getClass(), methodName, message);
                return null;
            }
        }
        return source;
    }
	
    /**
     * Verify that the magnet monitor site object has been defined.
     *
     * @exception AscServiceAbortException If unable to instantiate the
     *  magnet monitor site object.
     */
    private void verifyMagnetMonitorSiteObject()
        throws MagnetMonitorProcessorException {
        if ( magMonSite != null )
        {
            return;
        }
        if ( theSystemId == null )
        {
            String message = "System identifier either not defined or invalid";
            throw new MagnetMonitorProcessorException(message);
        }
        try {
	        magMonSite = new MagnetMonitorSite(isJunit);
	        magMonSite.selectSite( theSystemId );
        } catch (MagnetMonitorSiteException mmse) {
        	throw new MagnetMonitorProcessorException(mmse, mmse.getErrorCode());
        }
    }
}
